#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <cstdbool>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>

//命令行提示符格式
#define CLP "[%s@%s %s]# "
#define MAX_CLP 100
//命令行信息最大长度
#define MAX_COMLINE 1024
//命令行参数最大个数
#define MAX_GARGC 50
//环境变量表最大数量
#define MAX_GENV 500
int g_argc;
char* g_argv[MAX_GARGC];
//环境变量表
int g_envs;
char* g_env[MAX_GENV];
//最近一次进程退出时的退出码
int last_code = 0;

//导入环境变量
void EnvInit(){
    extern char** environ;
    memset(g_env,0,sizeof(g_env));
    g_envs = 0;
    //环境变量表要从系统文件中来
    //这从bash中获取
    for(int i = 0;environ[i]!=NULL;i++){
        g_env[i] = (char*) malloc(strlen(environ[i])+1);
        if(g_env[i] == NULL){
            perror("malloc");
            exit(3);
        }
        strcpy(g_env[i], environ[i]);
        g_envs++;
    }
    g_env[g_envs] = NULL;
    //导出环境变量
    for(int i = 0;i < g_envs;i++){
        putenv(g_env[i]);
    }
    environ = g_env;
}

//获取环境变量
char* GetUser(){
    return getenv("USER");
}
char* GetHostName(){
    return getenv("HOSTNAME");
}
//路径切割
std::string DirPwd(const char s[])
{
#define SLASH "/"
    std::string str = s;
    if(str == SLASH) return str;
    auto pos = str.rfind(SLASH);
    if(pos == std::string::npos) return "err";
    return str.substr(pos+1);
}
const char* GetPwd()
{
    //return getenv("PWD");
    return DirPwd(getenv("PWD")).c_str();
}
const char* GetHome(){
    return getenv("HOME");
}
//生成命令行提示符
void CommandLinePrompt(char buffer[])
{
    sprintf(buffer,CLP,GetUser(),GetHostName(),GetPwd());
    //sprintf(buffer,CLP,GetUser(),GetHostName(),DirPwd(GetPwd()).c_str());
}

void PrintCommandPrompt()
{
    char buffer[100];
    CommandLinePrompt(buffer);
    printf("%s",buffer);
    fflush(stdout);
}
char* GetCommandLine(char buff[]){
    char* c = fgets(buff,MAX_COMLINE,stdin);
    buff[strlen(buff)-1] = 0;
    return c;
}
void PrasCommandLine(char* buff){
    g_argc = 0;
    const char* sep = " ";
    for(g_argv[g_argc] = strtok(buff,sep); g_argv[g_argc] != NULL; g_argv[g_argc] = strtok(NULL,sep)){
        g_argc++;
    }
}
void CreateChildExecute(){
    int id = fork();
    if(id < 0)
    {
        perror("fork");
        exit(1);
    }
    else if (id == 0){
        //child
        execvp(g_argv[0],g_argv);
        exit(2);
    }
    //parent
    int status = 0;
    int rid = wait(&status);
    if(rid > 0)
        last_code = WEXITSTATUS(status);
}
void Cd(){
    std::string oldpwd = getenv("PWD");
    std::string where;
    if(g_argc == 1){
        where = GetHome();
        if(where.empty()) return;
        chdir(where.c_str());
    }
    else{
        where = g_argv[1];
        if(strcmp("-", g_argv[1]) == 0){
            where = getenv("OLDPWD");
        }
        else if(strcmp("~", g_argv[1]) == 0){
            where = GetHome();
            if(where.empty()) return;
        }
        chdir(where.c_str());
        //修改环境变量
    }
    //std::string old = std::string("OLDPWD=") + oldpwd;
    //char* arr = (char*)malloc(old.size()+1);
    //for(size_t i = 0;i<old.size();i++){
    //    arr[i] = old[i];
    //}
    //arr[old.size()] = 0;
    //putenv(arr);
}
void Echo(){
    if(g_argc == 2){
        std::string str = g_argv[1];
        if(str == "$?"){
            std::cout<<last_code<<std::endl;
        }
        else if(str[1] == '$'){
            std::string env_name = str.substr(1);
            const char* s = getenv(env_name.c_str());
            if(s)
                std::cout<<s<<std::endl;
        }
        else{
            std::cout<<str<<std::endl;
        }
    }
}

//判断内建命令
bool BinCommand(){
    std::string str = g_argv[0];
    if(str == "cd"){
        Cd();
        last_code = 0;
        return true;
    }
    else if(str == "echo"){
        Echo();
        last_code = 0;
        return true;
    }
   return false;            
}
void PrintArgv(){
    for(int i = 0;i < g_argc; i++){
        printf("g_argv[%d] : %s\n",i,g_argv[i]);
    }
}

void PrintEnv(){
    for(int i = 0; i < g_envs;i++){
        printf("g_env[%d] : %s\n",i,g_env[i]);
    }
}
int main()
{
    //获取环境变量表
    EnvInit();
    //PrintEnv();
    while(1){
        //1. 输出命令行提示符
        PrintCommandPrompt();
        //2. 获取用户输入信息
        char buff[MAX_COMLINE];
        char* c = GetCommandLine(buff);
        if(c == NULL)//读取用户输入信息失败
            continue;
        if(strlen(buff) == 0)//只输入了空格
            continue;
        //3. 命令行解析
        PrasCommandLine(buff);
        //4.内建命令
        if(BinCommand())
            continue;
        //5. 创建子进程执行命令
        CreateChildExecute();
    }
    return 0;
}





//#define MAXSIZE 1024 //用户输入信息的最大长度
//#define MAX_ARGV 50 //命令行参数表中最大个数
//#define MAX_CLP 200 //命令行提示符的最大长度
//#define CLP "[%s@%s %s]#"
//int g_argc = 0;
//char* g_argv[MAX_ARGV];
//
//char* GetUser(){
//    return getenv("USER");
//}
//char* GetHostName(){
//    return getenv("HOSTNAME");
//}
//char*  GetPwd(){
//    return getenv("PWD");
//}
//void CommidLinePrompt(char* c){
//    sprintf(c,CLP,GetUser(),GetHostName(),GetPwd());
//}
//void PrintCLP(){
//    char c[MAX_CLP];
//    CommidLinePrompt(c);
//    printf("%s",c);
//}
//char* GetEnterInformation(char* buff){
//    char* c = fgets(buff,MAXSIZE,stdin);
//    buff[strlen(buff)-1] = 0;
//    return c;
//}
//bool ParseCommidLinePtr(char* buff){
//#define SEP " "
//    g_argc = 0;
//    for(g_argv[g_argc] = strtok(buff,SEP); g_argv[g_argc] != NULL; g_argv[g_argc] = strtok(NULL,SEP)){
//        g_argc++;
//    }
//    if(g_argc == 0)
//        return true;
//    return true;
//}
//void CreateChildProcess(){
//    int id = fork();
//    if(id < 0){
//        perror("fork");
//        exit(2);
//    }
//    else if(id == 0){
//        execvp(g_argv[0],g_argv);
//        exit(3);
//    }
//    wait(NULL);
//}
//int main()
//{
//    while(1){
//        //1. 输出命令行提示符
//        PrintCLP();
//        //2. 获取用户输入信息
//        char buff[MAXSIZE];
//        char* c = GetEnterInformation(buff);
//        if(c == NULL){
//            //获取用户输入信息失败
//            continue;
//        }
//        if(strlen(buff) == 0){
//            //只输入了一个回车
//            continue;
//        }
//        //printf("%s\n",buff);
//
//        //3. 解析输入信息
//        //"ls -a -l" --> "ls" "-a" "-l"
//        ParseCommidLinePtr(buff);
//        //for(int i = 0;i < g_argc;i++){
//        //    printf("g_argv[%d] : %s\n",i,g_argv[i]);
//        //}
//        
//        //4. 创建子进程执行
//        CreateChildProcess();
//        }
//    return 0;
//}

//int main()
//{
//    while(1){
//        //获取命令行提示信息
//        printf("[%s@%s %s]@ ",getenv("USER"),getenv("HOSTNAME"),getenv("PWD"));
//        
//        //获取用户命令函参数
//        char buff[MAXSIZE];
//        char* c = fgets(buff,sizeof(buff),stdin);
//        if(c == NULL)
//            continue;
//        buff[strlen(buff)-1] = 0;
//        if(strlen(buff) == 0)
//            continue;
//        
//        //解析命令函参数
//        g_argc = 0;
//        const char* sep = " ";
//        for(g_argv[g_argc] = strtok(buff,sep); g_argv[g_argc]!=NULL; g_argv[g_argc] = strtok(NULL,sep)){
//            g_argc++;
//        }
//        
//        //创建子进程执行
//        int id = fork();
//        if(id < 0){
//            perror("fork");
//            exit(1);
//        }
//        else if(id == 0){
//            execvp(g_argv[0],g_argv);
//            exit(1);
//        }
//        //父进程等待
//        wait(NULL);
//    }
//
//    return 0;
//}
